package model

import (
	"fmt"
	"math"
	"time"
	"user_srv/basic/config"
)

// XqUserLocations 用户位置表模型
type XqUserLocations struct {
	Id        int64     `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
	UserId    int64     `gorm:"column:user_id;not null" json:"user_id"`
	Latitude  float64   `gorm:"column:latitude;type:decimal(10,7);not null" json:"latitude"`
	Longitude float64   `gorm:"column:longitude;type:decimal(10,7);not null" json:"longitude"`
	City      string    `gorm:"column:city;size:100;not null" json:"city"`
	Address   string    `gorm:"column:address;size:255" json:"address"`
	UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updated_at"`
	CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"`
}

func (x *XqUserLocations) TableName() string {
	return "xq_user_locations"
}

// InitTable 初始化表结构
func InitTable() error {
	return config.DB.AutoMigrate(&XqUserLocations{})
}

// Create 创建用户位置记录
func (x *XqUserLocations) Create() error {
	return config.DB.Create(&x).Error
}

// Update 更新用户位置记录
func (x *XqUserLocations) Update() error {
	return config.DB.Save(&x).Error
}

// Upsert 插入或更新用户位置记录
func (x *XqUserLocations) Upsert() error {
	// 添加调试信息
	fmt.Printf("开始Upsert操作: UserID=%d\n", x.UserId)

	// 检查记录是否存在
	var existing XqUserLocations
	err := config.DB.Where("user_id = ?", x.UserId).First(&existing).Error

	if err != nil {
		// 记录不存在，创建新记录
		fmt.Printf("记录不存在，创建新记录: UserID=%d\n", x.UserId)
		err = config.DB.Create(&x).Error
		if err != nil {
			fmt.Printf("创建记录失败: %v\n", err)
			return err
		}
		fmt.Printf("创建记录成功: UserID=%d\n", x.UserId)
	} else {
		// 记录存在，更新记录
		fmt.Printf("记录存在，更新记录: UserID=%d\n", x.UserId)
		fmt.Printf("更新数据: Lat=%.6f, Lng=%.6f, City=%s, Address=%s\n", x.Latitude, x.Longitude, x.City, x.Address)

		// 使用原生SQL直接更新，确保address字段被更新
		result := config.DB.Exec("UPDATE xq_user_locations SET latitude = ?, longitude = ?, city = ?, address = ?, updated_at = NOW() WHERE user_id = ?",
			x.Latitude, x.Longitude, x.City, x.Address, x.UserId)

		if result.Error != nil {
			fmt.Printf("更新记录失败: %v\n", result.Error)
			return result.Error
		}

		fmt.Printf("更新记录成功: UserID=%d, 影响行数: %d\n", x.UserId, result.RowsAffected)
	}

	return nil
}

// GetByUserId 根据用户ID获取位置信息
func (x *XqUserLocations) GetByUserId(userId int64) error {
	return config.DB.Where("user_id = ?", userId).First(&x).Error
}

// Delete 删除用户位置记录
func (x *XqUserLocations) Delete() error {
	return config.DB.Delete(&x).Error
}

// GetNearbyUsers 获取附近的用户（使用原生SQL进行地理计算）
func GetNearbyUsers(userId int64, latitude, longitude float64, radius int32) ([]XqUserLocations, error) {
	var locations []XqUserLocations

	// 使用Haversine公式计算距离的SQL查询
	query := `
		SELECT 
			ul.user_id,
			ul.latitude,
			ul.longitude,
			ul.city,
			ul.address,
			ul.updated_at,
			ul.created_at,
			(
				6371 * acos(
					cos(radians(?)) * cos(radians(ul.latitude)) * 
					cos(radians(ul.longitude) - radians(?)) + 
					sin(radians(?)) * sin(radians(ul.latitude))
				)
			) AS distance
		FROM xq_user_locations ul
		WHERE ul.user_id != ?
		HAVING distance <= ?
		ORDER BY distance ASC
		LIMIT 50
	`

	err := config.DB.Raw(query, latitude, longitude, latitude, userId, radius).Scan(&locations).Error
	return locations, err
}

// GetUsersInRadius 获取指定半径内的用户（使用边界框优化）
func GetUsersInRadius(userId int64, latitude, longitude float64, radius int32) ([]XqUserLocations, error) {
	var locations []XqUserLocations

	// 计算边界框（简化计算，1度约等于111公里）
	latRange := float64(radius) / 111.0
	lngRange := float64(radius) / (111.0 * math.Cos(latitude*math.Pi/180.0))

	minLat := latitude - latRange
	maxLat := latitude + latRange
	minLng := longitude - lngRange
	maxLng := longitude + lngRange

	query := `
		SELECT 
			ul.user_id,
			ul.latitude,
			ul.longitude,
			ul.city,
			ul.address,
			ul.updated_at,
			ul.created_at,
			(
				6371 * acos(
					cos(radians(?)) * cos(radians(ul.latitude)) * 
					cos(radians(ul.longitude) - radians(?)) + 
					sin(radians(?)) * sin(radians(ul.latitude))
				)
			) AS distance
		FROM xq_user_locations ul
		WHERE ul.user_id != ?
		AND ul.latitude BETWEEN ? AND ?
		AND ul.longitude BETWEEN ? AND ?
		HAVING distance <= ?
		ORDER BY distance ASC
		LIMIT 50
	`

	err := config.DB.Raw(query, latitude, longitude, latitude, userId, minLat, maxLat, minLng, maxLng, radius).Scan(&locations).Error
	return locations, err
}
